package main

import (
	"fmt"
	"io"
	"log"
	"os"
	"time"

	adminController "go-frame/src/server-admin/controller"
	rasterTileController "go-frame/src/server-main/controller"

	adminDao "go-frame/src/server-admin/dao"
	"go-frame/src/server-admin/middleware"
	adminModels "go-frame/src/server-admin/models"
	adminRabbitMQ "go-frame/src/server-admin/rabbitmq"
	adminService "go-frame/src/server-admin/service"
	common "go-frame/src/server-common"
	serverConfig "go-frame/src/server-config"
	"go-frame/src/server-main/controller"
	"go-frame/src/server-main/dao"
	"go-frame/src/server-main/models"
	"go-frame/src/server-main/service"

	"github.com/gin-gonic/gin"
	"gorm.io/driver/postgres"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"

	"github.com/gin-contrib/cors"

	_ "go-frame/docs" // docs is generated by Swag CLI, you have to import it.

	swaggerFiles "github.com/swaggo/files"
	ginSwagger "github.com/swaggo/gin-swagger"
)

// @title Gin GORM Swagger Example API
// @version 1.0
// @description This is a sample server for a Gin GORM Swagger project.
// @host localhost:8081
// @BasePath /
// @securityDefinitions.apikey ApiKeyAuth
// @in header
// @name Authorization

func main() {
	var config *serverConfig.Config
	var err error

	// Load configuration
	config, err = serverConfig.LoadConfig()
	if err != nil {
		log.Fatalf("failed to load config: %v", err)
	}

	// Initialize RabbitMQ Client
	rmqClient, err := adminRabbitMQ.NewRabbitMQClient(
		config.RabbitMQ.Host,
		config.RabbitMQ.Port,
		config.RabbitMQ.Username,
		config.RabbitMQ.Password,
	)
	if err != nil {
		log.Fatalf("failed to connect to RabbitMQ: %v", err)
	}
	rmqClient.DeclareQueue("test_queue")
	rmqClient.Publish("test_queue", "Hello, 我正在测试RabbitMQ-0!")
	rmqClient.Publish("test_queue", "Hello, 我正在测试RabbitMQ-1!")
	rmqClient.Publish("test_queue", "Hello, 我正在测试RabbitMQ-2!")

	ch, err := rmqClient.Consume("test_queue")

	go func() {
		for msg := range ch {
			time.Sleep(time.Second * 2)
			fmt.Println("Received message:", string(msg.Body))
		}
	}()
	defer rmqClient.Close()

	// Initialize GORM
	newLogger := logger.New(
		log.New(os.Stdout, "\r\n", log.LstdFlags),
		logger.Config{
			SlowThreshold:             time.Second, // Slow SQL threshold
			LogLevel:                  logger.Info, // Log level
			IgnoreRecordNotFoundError: true,        // Ignore ErrRecordNotFound error for logger
			Colorful:                  true,        // Disable color
		},
	)

	dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%d sslmode=%s TimeZone=Asia/Shanghai",
		config.Database.Host, config.Database.User, config.Database.Password,
		config.Database.DBName, config.Database.Port, config.Database.SSLMode)
	db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{
		Logger: newLogger,
	})
	if err != nil {
		log.Fatalf("failed to connect database: %v", err)
	}

	// Migrate the schema
	db.AutoMigrate(&models.Product{}, &adminModels.User{})

	// Create the log directory if it doesn't exist
	logPath := ".\\servername-logs"
	if err := os.MkdirAll(logPath, os.ModePerm); err != nil {
		log.Fatalf("failed to create log directory: %v", err)
	}

	// Create a log file with daily rotation
	logFileName := logPath + "\\gin_" + time.Now().Format("2006-01-02") + ".log"
	logFile, err := os.Create(logFileName)
	if err != nil {
		log.Fatalf("failed to create log file: %v", err)
	}
	defer logFile.Close()

	// Set Gin to output logs to the file
	gin.DefaultWriter = io.MultiWriter(logFile, os.Stdout)

	// Initialize Gin
	r := gin.Default()

	// Configure CORS middleware
	r.Use(cors.New(cors.Config{
		AllowOrigins:     []string{"*"},
		AllowMethods:     []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
		AllowHeaders:     []string{"Origin", "Content-Type", "Accept", "Authorization"},
		ExposeHeaders:    []string{"Content-Length"},
		AllowCredentials: true,
		MaxAge:           12 * time.Hour,
	}))

	// Initialize DAO, Service, Controller
	productDAO := dao.NewProductDAO(db)
	productService := service.NewProductService(productDAO)
	productController := controller.NewProductController(productService)

	// Load configuration
	config, err = serverConfig.LoadConfig()
	if err != nil {
		log.Fatalf("failed to load config: %v", err)
	}

	// 初始化 admin 模块的 DAO, Service, Controller
	userDAO := adminDao.NewUserDAO(db)
	authService := adminService.NewAuthService(userDAO, config.JWT.ExpirationMilliseconds, config.JWT.Secret)
	authController := adminController.NewAuthController(authService)

	// 初始化 rasterTile 模块的 Controller
	rasterTileController := rasterTileController.NewRasterTileController(config.Sqlite.TileDataPath)

	// 初始化认证中间件
	authMiddleware := middleware.AuthMiddleware(authService)

	// Swagger endpoint
	r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))

	// Raster Tile endpoint
	r.GET("/rasterTile/:rasterName/:z/:x/:y", rasterTileController.GetTile)

	// Admin 模块路由 (无需认证)
	r.POST("/register", authController.Register)
	r.POST("/login", authController.Login)

	// 需要认证的路由组
	authGroup := r.Group("/")
	authGroup.Use(authMiddleware)
	{
		// 获取当前登录用户信息
		authGroup.GET("/profile", authController.GetProfile)

		// API endpoints
		productGroup := authGroup.Group("/products")
		{
			productGroup.GET("/", productController.GetAllProducts)
			productGroup.POST("/", productController.CreateProduct)
			productGroup.GET("/:id", productController.GetProductByID)
			productGroup.PUT("/:id", productController.UpdateProduct)
			productGroup.DELETE("/:id", productController.DeleteProduct)
		}
	}

	// Test SHP file parsing
	shpFilePath := "tmp/test_files/point.shp" // Assuming a sample.shp exists here
	shpInfo, err := common.ParseShpFile(shpFilePath)
	if err != nil {
		log.Printf("Error parsing SHP file %s: %v", shpFilePath, err)
	} else {
		log.Printf("Successfully parsed SHP file: %s", shpFilePath)
		log.Printf("  Shape Type: %s", shpInfo.ShapeType)
		log.Printf("  Number of Shapes: %d", shpInfo.NumShapes)
		log.Printf("  Fields:")
		for _, field := range shpInfo.Fields {
			log.Printf("    - Name: %s, Type: %s", field.String(), string(field.Fieldtype))
		}
	}

	log.Fatal(r.Run(fmt.Sprintf(":%d", config.Server.Port)))
}
